#! /usr/bin/env Python3
#coding=utf-8
"""
东方财富网股票数据爬虫模块
作者: KydGroups
版本: 1.0.0
完成日期: 2024-03-04
修改记录:
"""

import requests

from KydPyPub.Sys import TypeConvert #添加字符串转换模块

class DfcfStock():
    """
    从东方财富网上爬取股票各种信息的类
    """
    def __init__(self):
        """
        :DESCRIPTION:
            初始化函数
        :PARAMS:
            nothing
        :RETURNS:
            nothing
        """
        self.strBonusJsonUrlFormat= ('https://datacenter-web.eastmoney.com/api/data/v1/get?reportName=RPT_SHAREBONUS_DET&columns=ALL'+
                                     '&sortColumns=PLAN_NOTICE_DATE&sortTypes=1&source=WEB&client=WEB&filter=(SECURITY_CODE="%s")')  # 分红jquery查询格式化表头
        self.urlheaders = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36' }
        self.__strStoreCode = "" #股票存储代码
        self.__strStockCode = "" #股票代码
        self.dictFunc = {'Bonus': True,#是否有爬取股票分红数据功能
                         'Fina': False,  # 是否有爬取股票财务数据功能
                         'Trade': False,  # 是否有爬取股票交易时间的数据功能
                         'Close': False}  # 是否有爬取股票收盘后的数据功能


    def SetStoreCode(self, strCode:str=''):
        """
        :DESCRIPTION:
            设置股票存储代码,注意这里都是使用存储代码
        :PARAMS:
            strCode:股票的存储代码
        :RETURNS:
            True:设置成功 False:设置失败
        """
        if not strCode: #如果没有传入参数
            return False
        if not isinstance(strCode, str): #如果传入的参数不是str类型
            return False
        try:
            if len( strCode) != 8:#如果传入的代码长度不为8
                self.__strStoreCode = ""
                self.__strStockCode = ""
                return False
            else:
                self.__strStoreCode = strCode #设置股票存储代码
                self.__strStockCode = strCode[2:] #设置股票代码
                return True
        except:
            return False


    def GetCrawlerFunction(self):
        """
        :DESCRIPTION:
            获取爬虫的功能设置
        :PARAMS:
            nothing
        :RETURNS:
            None:出错 Dict:完成功能字典
        """
        return self.dictFunc


    def CrawBonusData(self):
        """
        :DESCRITION:
            爬取股票分红信息
        :PARAMS:
            nothing
        :RETURNS:
            None:出错 List:爬取到的股票分红数据列表
        """
        try:
            if not self.__strStockCode:#如果没有设置股票代码
                strError = TypeConvert.StrToColorStr("使用Stock_DFCF_Crawler类爬取股票分红数据时_没有设置股票代码!", 'alarm')
                print(strError)
                return None
            url = self.strBonusJsonUrlFormat % self.__strStockCode#格式化基金基本信息网址
            print("正在从东方财富网站下载股票 %s 分红记录!" % self.__strStockCode)
            listGet = self.__GetBonusJsonData(url) #获取json数据
            if not listGet:#如果没有下载到数据
                return None
            else:
                listReturn = list() #返回的记录字典列表
                for item in listGet:#循环处理每一条记录
                    if item['ASSIGN_PROGRESS'] != "实施分配":#如果不是实施分配的记录,则不作处理
                        continue
                    elif not item['EQUITY_RECORD_DATE']:#如果没有股权登记日期则不作处理
                        continue
                    else:
                        dictBonus = dict() #分红记录字典
                        dictBonus['StoreCode'] = self.__strStoreCode #设置股票存储代码
                        dictBonus['StockCode'] = self.__strStockCode #设置股票代码
                        dictBonus['AnnDate'] = item['NOTICE_DATE'][:10] #公告日期
                        if not item['BONUS_RATIO']:#如果没有送股数
                            dictBonus['BonusShares'] = 0.00 #盈利每股送股数,保存５位有效数字,要交税
                        else:
                            dictBonus['BonusShares'] = round((item['BONUS_RATIO']/10.0), 6)#盈利每股送股数,保存6位有效数字,要交税
                        if not item['IT_RATIO']:#如果没有公积金转增股数
                            dictBonus['AddShares'] = 0.00 #公积金每股转增股数,保存6位有效数字,不用交税
                        else:
                            dictBonus['AddShares'] = round((item['IT_RATIO']/10.0), 6) #公积金每股转增股数,保存6位有效数字,不用交税
                        if not item['PRETAX_BONUS_RMB']:#如果没有税前分红金额
                            dictBonus['DiviValue'] = 0.00 #每股派息,保存6位有效数字,要交税
                        else:
                            dictBonus['DiviValue'] = round( (item['PRETAX_BONUS_RMB']/10.0), 6) #每股派息,保存6位有效数字,要交税
                        dictBonus['RegDate'] = item['EQUITY_RECORD_DATE'][:10] #股权登记日
                        dictBonus['DiviDate'] = item['EX_DIVIDEND_DATE'][:10] #除权除息日
                        dictBonus['ListDate'] = item['EX_DIVIDEND_DATE'][:10] #红股上市日期
                        dictBonus['Remark'] = 'Yes'

                        if (dictBonus['DiviValue']<=0.0) and (dictBonus['BonusShares']<=0.0) and (dictBonus['AddShares'] <= 0.0):
                            continue#如果三个数字都为0，则跳过该行
                        else:
                            listReturn.append(dictBonus) #将结果添加到列表中
                if not listReturn:#如果没有返回数据
                    return None
                else:
                    listReturn.sort(key=lambda x:x['RegDate'], reverse=True)
                    return listReturn
        except:
            return None

    
    def __GetBonusJsonData(self, strUrl:str=""):
        """
        :DESCRIPTION:
            从东方财富网获取股票分红数据的json数据
        :PARAMS:
            strUrl: 要获取的json数据的Url地址
        :RETURNS:
            None:出错 Json:返回获取到的json数据的字符串
        """
        try:
            if not strUrl: #如果没有传入参数
                return None
            else:
                try:
                    print("正在从东方财富网站下载股票 %s 分红数据!" % self.__strStockCode)
                    resp=requests.get(strUrl)
                    if not resp:#如果没有返回结果
                        strError = TypeConvert.StrToColorStr("从东方财富网站下载股票 %s 分红数据时，没有返回结果!" % self.__strStockCode, 'alarm')
                        print(strError)
                        return None
                    else:
                        json_data=resp.json()
                        list_data = json_data['result']['data']
                        print("从东方财富网站下载股票 %s 分红数据成功!" % self.__strStockCode)
                        return list_data
                except: #如果出现错误，则返回
                    strError = TypeConvert.StrToColorStr("从东方财富网站下载股票 %s 分红数据失败!" % self.__strStockCode, 'alarm')
                    print(strError)
                    return None
        except:
            return None
